package com.yc.testupload.crawler.strategy;

import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 策略选择器，根据URL选择合适的爬取策略
 */
public class StrategySelector {
    // 使用类名作为logger名称，确保日志记录准确
    private static final Logger logger = LogManager.getLogger(StrategySelector.class);
    private final List<CrawlingStrategy> strategies;
    
    public StrategySelector() {
        // 初始化策略列表
        strategies = new ArrayList<>();
        // 添加特定网站的策略（放在前面，优先级更高）
        strategies.add(new MianshiyaCrawlingStrategy());
        strategies.add(new NiuKeCrawlingStrategy());
        // 添加Selenium策略，可以处理需要JavaScript渲染的动态网页
        strategies.add(new SeleniumCrawlingStrategy());
        // 添加通用策略（放在后面，作为备选）
        strategies.add(new JSStateCrawlingStrategy());
        strategies.add(new CommonQuestionAnswerStrategy());
        
        logger.info("策略选择器初始化完成，加载了{}种爬取策略", strategies.size());
    }
    
    /**
     * 根据URL选择合适的爬取策略
     * @param url 要爬取的URL
     * @return 适合的爬取策略
     */
    public CrawlingStrategy selectStrategy(String url) {
        if (url == null || url.trim().isEmpty()) {
            logger.warn("URL为空，返回默认策略");
            return strategies.get(strategies.size() - 1); // 返回最后一个策略作为默认
        }
        
        // 遍历策略列表，找到第一个适用的策略
        for (CrawlingStrategy strategy : strategies) {
            try {
                if (strategy.isApplicable(url)) {
                    logger.info("为URL {} 选择策略: {}", url, strategy.getClass().getSimpleName());
                    return strategy;
                }
            } catch (Exception e) {
                logger.error("检查策略 {} 适用性时出错: {}", strategy.getClass().getSimpleName(), e.getMessage());
            }
        }
        
        // 如果没有找到适用的策略，返回最后一个策略作为默认
        logger.warn("没有找到适用的策略，返回默认策略");
        return strategies.get(strategies.size() - 1);
    }
    
    /**
     * 根据URL提取面试题，采用多级尝试机制确保提取成功率
     * @param url 要爬取的URL
     * @param html HTML内容
     * @return 提取的面试题文本
     */
    public String extractQuestions(String url, String html) {
        logger.info("开始提取面试题，URL: {}", url);
        
        // 记录开始时间，用于性能监控
        long startTime = System.currentTimeMillis();
        
        // 使用AtomicReference存储提取结果
        AtomicReference<String> resultRef = new AtomicReference<>("");
        
        try {
            // 尝试使用选中的策略提取面试题
            CrawlingStrategy selectedStrategy = selectStrategy(url);
            
            // 特殊处理：如果是面试呀网站的策略，直接从URL抓取
            if (selectedStrategy instanceof MianshiyaCrawlingStrategy) {
                logger.info("检测到面试呀网站，使用专用方法直接从URL抓取内容");
                MianshiyaCrawlingStrategy mianshiyaStrategy = (MianshiyaCrawlingStrategy) selectedStrategy;
                String result = mianshiyaStrategy.extractQuestionsFromUrl(url);
                
                if (!result.isEmpty()) {
                    resultRef.set(result);
                    logger.info("使用面试呀专用策略成功抓取面试题，结果长度: {}字符", result.length());
                }
            } else {
                // 对于其他策略，使用常规的HTML解析方式
                if (html == null || html.isEmpty()) {
                    logger.warn("HTML内容为空，无法提取面试题");
                    return "";
                }
                
                String result = selectedStrategy.extractQuestions(html);
                
                if (!result.isEmpty()) {
                    resultRef.set(result);
                    logger.info("使用策略 {} 成功提取面试题，结果长度: {}字符", 
                                selectedStrategy.getClass().getSimpleName(), result.length());
                }
            }
            
            if (resultRef.get().isEmpty()) {
                logger.warn("策略 {} 未能提取到面试题，尝试使用备选策略", 
                            selectedStrategy.getClass().getSimpleName());
                
                // 如果选中的策略未能提取到内容，尝试其他所有策略
                for (CrawlingStrategy strategy : strategies) {
                    if (strategy != selectedStrategy) {
                        try {
                            logger.info("尝试使用备选策略: {}", strategy.getClass().getSimpleName());
                            
                            // 如果备选策略是面试呀策略，使用其专用方法
                            if (strategy instanceof MianshiyaCrawlingStrategy) {
                                MianshiyaCrawlingStrategy mianshiyaStrategy = (MianshiyaCrawlingStrategy) strategy;
                                String result = mianshiyaStrategy.extractQuestionsFromUrl(url);
                                if (!result.isEmpty()) {
                                    resultRef.set(result);
                                    logger.info("备选策略 {} 成功抓取面试题，结果长度: {}字符", 
                                                strategy.getClass().getSimpleName(), result.length());
                                    break;
                                }
                            } else {
                                // 其他策略使用常规HTML解析
                                if (html != null && !html.isEmpty()) {
                                    String result = strategy.extractQuestions(html);
                                    if (!result.isEmpty()) {
                                        resultRef.set(result);
                                        logger.info("备选策略 {} 成功提取面试题，结果长度: {}字符", 
                                                    strategy.getClass().getSimpleName(), result.length());
                                        break;
                                    }
                                }
                            }
                        } catch (Exception e) {
                            logger.error("使用备选策略 {} 提取面试题时出错: {}", 
                                         strategy.getClass().getSimpleName(), e.getMessage());
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("提取面试题时出错: {}", e.getMessage());
        } finally {
            // 记录结束时间，计算耗时
            long endTime = System.currentTimeMillis();
            logger.info("面试题提取完成，耗时: {}毫秒，最终结果长度: {}字符", 
                       (endTime - startTime), resultRef.get().length());
        }
        
        return resultRef.get();
    }
    
    /**
     * 根据URL提取页面标题
     * @param url 要爬取的URL
     * @param html HTML内容
     * @return 提取的标题
     */
    public String extractTitle(String url, String html) {
        if (html == null || html.isEmpty()) {
            logger.warn("HTML内容为空，无法提取标题");
            return "未命名页面";
        }
        
        try {
            CrawlingStrategy strategy = selectStrategy(url);
            String title = strategy.extractTitle(html);
            
            // 如果提取的标题为空，尝试使用备选方法
            if (title == null || title.isEmpty()) {
                logger.warn("策略 {} 未能提取到标题，使用备选方法", strategy.getClass().getSimpleName());
                
                // 直接从HTML中提取标题
                for (CrawlingStrategy altStrategy : strategies) {
                    try {
                        title = altStrategy.extractTitle(html);
                        if (title != null && !title.isEmpty()) {
                            logger.info("使用备选策略 {} 成功提取标题", altStrategy.getClass().getSimpleName());
                            break;
                        }
                    } catch (Exception e) {
                        logger.error("使用备选策略 {} 提取标题时出错: {}", 
                                     altStrategy.getClass().getSimpleName(), e.getMessage());
                    }
                }
                
                // 如果所有策略都未能提取到标题，返回默认标题
                if (title == null || title.isEmpty()) {
                    title = "未命名页面";
                }
            }
            
            logger.info("成功提取标题: {}", title);
            return title;
        } catch (Exception e) {
            logger.error("提取标题时出错: {}", e.getMessage());
            return "未命名页面";
        }
    }
    
    /**
     * 获取所有可用的策略
     * @return 策略列表
     */
    public List<CrawlingStrategy> getStrategies() {
        return new ArrayList<>(strategies);
    }
}